﻿using Grand.Business.Core.Interfaces.Catalog.Directory;
using Grand.Business.Core.Interfaces.Checkout.Shipping;
using Grand.Business.Core.Interfaces.Common.Configuration;
using Grand.Business.Core.Interfaces.Common.Directory;
using Grand.Business.Core.Interfaces.Common.Localization;
using Grand.Business.Core.Interfaces.Common.Stores;
using Grand.Domain.Permissions;
using Grand.Domain.Directory;
using Grand.Web.Common.Controllers;
using Grand.Web.Common.DataSource;
using Grand.Web.Common.Filters;
using Grand.Web.Common.Security.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Shipping.ByWeight.Domain;
using Shipping.ByWeight.Models;
using Shipping.ByWeight.Services;

namespace Shipping.ByWeight.Areas.Admin.Controllers;

[AuthorizeAdmin]
[Area("Admin")]
[PermissionAuthorize(PermissionSystemName.ShippingSettings)]
public class ShippingByWeightController : BaseShippingController
{
    private readonly ICountryService _countryService;
    private readonly ICurrencyService _currencyService;
    private readonly CurrencySettings _currencySettings;
    private readonly IMeasureService _measureService;
    private readonly MeasureSettings _measureSettings;
    private readonly ISettingService _settingService;
    private readonly IShippingByWeightService _shippingByWeightService;
    private readonly ByWeightShippingSettings _shippingByWeightSettings;
    private readonly IShippingMethodService _shippingMethodService;
    private readonly IStoreService _storeService;
    private readonly ITranslationService _translationService;
    private readonly IWarehouseService _warehouseService;

    public ShippingByWeightController(
        IWarehouseService warehouseService,
        IShippingMethodService shippingMethodService,
        IStoreService storeService,
        ICountryService countryService,
        ByWeightShippingSettings shippingByWeightSettings,
        IShippingByWeightService shippingByWeightService,
        ISettingService settingService,
        ITranslationService translationService,
        ICurrencyService currencyService,
        CurrencySettings currencySettings,
        IMeasureService measureService,
        MeasureSettings measureSettings)
    {
        _warehouseService = warehouseService;
        _shippingMethodService = shippingMethodService;
        _storeService = storeService;
        _countryService = countryService;
        _shippingByWeightSettings = shippingByWeightSettings;
        _shippingByWeightService = shippingByWeightService;
        _settingService = settingService;
        _translationService = translationService;
        _currencyService = currencyService;
        _currencySettings = currencySettings;
        _measureService = measureService;
        _measureSettings = measureSettings;
    }

    public IActionResult Configure()
    {
        var model = new ShippingByWeightListModel {
            LimitMethodsToCreated = _shippingByWeightSettings.LimitMethodsToCreated,
            DisplayOrder = _shippingByWeightSettings.DisplayOrder
        };

        return View(model);
    }

    [HttpPost]
    [AutoValidateAntiforgeryToken]
    public async Task<IActionResult> SaveGeneralSettings(ShippingByWeightListModel model)
    {
        //save settings
        _shippingByWeightSettings.LimitMethodsToCreated = model.LimitMethodsToCreated;
        _shippingByWeightSettings.DisplayOrder = model.DisplayOrder;

        await _settingService.SaveSetting(_shippingByWeightSettings);

        return Json(new { Result = true });
    }


    [HttpPost]
    [AutoValidateAntiforgeryToken]
    public async Task<IActionResult> RatesList(DataSourceRequest command)
    {
        var records = await _shippingByWeightService.GetAll(command.Page - 1, command.PageSize);

        var sbwModel = new List<ShippingByWeightModel>();
        foreach (var x in records)
        {
            var m = new ShippingByWeightModel {
                Id = x.Id,
                StoreId = x.StoreId,
                WarehouseId = x.WarehouseId,
                ShippingMethodId = x.ShippingMethodId,
                CountryId = x.CountryId,
                From = x.From,
                To = x.To,
                AdditionalFixedCost = x.AdditionalFixedCost,
                PercentageRateOfSubtotal = x.PercentageRateOfSubtotal,
                RatePerWeightUnit = x.RatePerWeightUnit,
                LowerWeightLimit = x.LowerWeightLimit
            };
            //shipping method
            var shippingMethod = await _shippingMethodService.GetShippingMethodById(x.ShippingMethodId);
            m.ShippingMethodName = shippingMethod != null ? shippingMethod.Name : "Unavailable";
            //store
            var store = await _storeService.GetStoreById(x.StoreId);
            m.StoreName = store != null ? store.Shortcut : "*";
            //warehouse
            var warehouse = await _warehouseService.GetWarehouseById(x.WarehouseId);
            m.WarehouseName = warehouse != null ? warehouse.Name : "*";
            //country
            var c = await _countryService.GetCountryById(x.CountryId);
            m.CountryName = c != null ? c.Name : "*";
            //state
            var s = c?.StateProvinces.FirstOrDefault(y => y.Id == x.StateProvinceId);
            m.StateProvinceName = s != null ? s.Name : "*";
            //zip
            m.Zip = !string.IsNullOrEmpty(x.Zip) ? x.Zip : "*";


            var htmlSb = new StringBuilder("<div>");
            htmlSb.Append($"{_translationService.GetResource("Plugins.Shipping.ByWeight.Fields.From")}: {m.From}");
            htmlSb.Append("<br />");
            htmlSb.Append($"{_translationService.GetResource("Plugins.Shipping.ByWeight.Fields.To")}: {m.To}");
            htmlSb.Append("<br />");
            htmlSb.Append(
                $"{_translationService.GetResource("Plugins.Shipping.ByWeight.Fields.AdditionalFixedCost")}: {m.AdditionalFixedCost}");
            htmlSb.Append("<br />");
            htmlSb.Append(
                $"{_translationService.GetResource("Plugins.Shipping.ByWeight.Fields.RatePerWeightUnit")}: {m.RatePerWeightUnit}");
            htmlSb.Append("<br />");
            htmlSb.Append(
                $"{_translationService.GetResource("Plugins.Shipping.ByWeight.Fields.LowerWeightLimit")}: {m.LowerWeightLimit}");
            htmlSb.Append("<br />");
            htmlSb.Append(
                $"{_translationService.GetResource("Plugins.Shipping.ByWeight.Fields.PercentageRateOfSubtotal")}: {m.PercentageRateOfSubtotal}");

            htmlSb.Append("</div>");
            m.DataHtml = htmlSb.ToString();

            sbwModel.Add(m);
        }

        var gridModel = new DataSourceResult {
            Data = sbwModel,
            Total = records.TotalCount
        };

        return Json(gridModel);
    }

    [HttpPost]
    [AutoValidateAntiforgeryToken]
    public async Task<IActionResult> RateDelete(string id)
    {
        var sbw = await _shippingByWeightService.GetById(id);
        if (sbw != null)
            await _shippingByWeightService.DeleteShippingByWeightRecord(sbw);

        return new JsonResult("");
    }

    public async Task<IActionResult> AddPopup()
    {
        var model = new ShippingByWeightModel {
            PrimaryStoreCurrencyCode =
                (await _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)).CurrencyCode,
            BaseWeightIn = (await _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId)).Name,
            To = 1000000
        };

        var shippingMethods = await _shippingMethodService.GetAllShippingMethods();
        if (shippingMethods.Count == 0)
            return Content("No shipping methods can be loaded");

        //stores
        model.AvailableStores.Add(new SelectListItem { Text = "*", Value = " " });
        foreach (var store in await _storeService.GetAllStores())
            model.AvailableStores.Add(new SelectListItem { Text = store.Shortcut, Value = store.Id });
        //warehouses
        model.AvailableWarehouses.Add(new SelectListItem { Text = "*", Value = " " });
        foreach (var warehouses in await _warehouseService.GetAllWarehouses())
            model.AvailableWarehouses.Add(new SelectListItem { Text = warehouses.Name, Value = warehouses.Id });
        //shipping methods
        foreach (var sm in shippingMethods)
            model.AvailableShippingMethods.Add(new SelectListItem { Text = sm.Name, Value = sm.Id });
        //countries
        model.AvailableCountries.Add(new SelectListItem { Text = "*", Value = " " });
        var countries = await _countryService.GetAllCountries(showHidden: true);
        foreach (var c in countries)
            model.AvailableCountries.Add(new SelectListItem { Text = c.Name, Value = c.Id });
        //states
        model.AvailableStates.Add(new SelectListItem { Text = "*", Value = "" });

        return View(model);
    }

    [HttpPost]
    [AutoValidateAntiforgeryToken]
    public async Task<IActionResult> AddPopup(ShippingByWeightModel model)
    {
        var sbw = new ShippingByWeightRecord {
            StoreId = model.StoreId,
            WarehouseId = model.WarehouseId,
            CountryId = model.CountryId,
            StateProvinceId = model.StateProvinceId,
            Zip = model.Zip == "*" ? null : model.Zip,
            ShippingMethodId = model.ShippingMethodId,
            From = model.From,
            To = model.To,
            AdditionalFixedCost = model.AdditionalFixedCost,
            RatePerWeightUnit = model.RatePerWeightUnit,
            PercentageRateOfSubtotal = model.PercentageRateOfSubtotal,
            LowerWeightLimit = model.LowerWeightLimit
        };
        await _shippingByWeightService.InsertShippingByWeightRecord(sbw);

        ViewBag.RefreshPage = true;

        return View(model);
    }

    //edit
    public async Task<IActionResult> EditPopup(string id)
    {
        var sbw = await _shippingByWeightService.GetById(id);
        if (sbw == null)
            //No record found with the specified id
            return RedirectToAction("Configure");

        var model = new ShippingByWeightModel {
            Id = sbw.Id,
            StoreId = sbw.StoreId,
            WarehouseId = sbw.WarehouseId,
            CountryId = sbw.CountryId,
            StateProvinceId = sbw.StateProvinceId,
            Zip = sbw.Zip,
            ShippingMethodId = sbw.ShippingMethodId,
            From = sbw.From,
            To = sbw.To,
            AdditionalFixedCost = sbw.AdditionalFixedCost,
            PercentageRateOfSubtotal = sbw.PercentageRateOfSubtotal,
            RatePerWeightUnit = sbw.RatePerWeightUnit,
            LowerWeightLimit = sbw.LowerWeightLimit,
            PrimaryStoreCurrencyCode =
                (await _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)).CurrencyCode,
            BaseWeightIn = (await _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId)).Name
        };

        var shippingMethods = await _shippingMethodService.GetAllShippingMethods();
        if (shippingMethods.Count == 0)
            return Content("No shipping methods can be loaded");

        var selectedStore = await _storeService.GetStoreById(sbw.StoreId);
        var selectedWarehouse = await _warehouseService.GetWarehouseById(sbw.WarehouseId);
        var selectedShippingMethod = await _shippingMethodService.GetShippingMethodById(sbw.ShippingMethodId);
        var selectedCountry = await _countryService.GetCountryById(sbw.CountryId);
        var selectedState = selectedCountry?.StateProvinces.FirstOrDefault(x => x.Id == sbw.StateProvinceId);
        //stores
        model.AvailableStores.Add(new SelectListItem { Text = "*", Value = "" });
        foreach (var store in await _storeService.GetAllStores())
            model.AvailableStores.Add(new SelectListItem {
                Text = store.Shortcut, Value = store.Id,
                Selected = selectedStore != null && store.Id == selectedStore.Id
            });
        //warehouses
        model.AvailableWarehouses.Add(new SelectListItem { Text = "*", Value = "" });
        foreach (var warehouse in await _warehouseService.GetAllWarehouses())
            model.AvailableWarehouses.Add(new SelectListItem {
                Text = warehouse.Name, Value = warehouse.Id,
                Selected = selectedWarehouse != null && warehouse.Id == selectedWarehouse.Id
            });
        //shipping methods
        foreach (var sm in shippingMethods)
            model.AvailableShippingMethods.Add(new SelectListItem {
                Text = sm.Name, Value = sm.Id,
                Selected = selectedShippingMethod != null && sm.Id == selectedShippingMethod.Id
            });
        //countries
        model.AvailableCountries.Add(new SelectListItem { Text = "*", Value = "" });
        var countries = await _countryService.GetAllCountries(showHidden: true);
        foreach (var c in countries)
            model.AvailableCountries.Add(new SelectListItem
                { Text = c.Name, Value = c.Id, Selected = selectedCountry != null && c.Id == selectedCountry.Id });
        //states
        var states = selectedCountry != null
            ? await _countryService.GetStateProvincesByCountryId(selectedCountry.Id)
            : new List<StateProvince>();
        model.AvailableStates.Add(new SelectListItem { Text = "*", Value = "" });
        foreach (var s in states)
            model.AvailableStates.Add(new SelectListItem
                { Text = s.Name, Value = s.Id, Selected = selectedState != null && s.Id == selectedState.Id });

        return View(model);
    }

    [HttpPost]
    [AutoValidateAntiforgeryToken]
    public async Task<IActionResult> EditPopup(ShippingByWeightModel model)
    {
        var sbw = await _shippingByWeightService.GetById(model.Id);
        if (sbw == null)
            //No record found with the specified id
            return RedirectToAction("Configure");

        sbw.StoreId = model.StoreId;
        sbw.WarehouseId = model.WarehouseId;
        sbw.CountryId = model.CountryId;
        sbw.StateProvinceId = model.StateProvinceId;
        sbw.Zip = model.Zip == "*" ? null : model.Zip;
        sbw.ShippingMethodId = model.ShippingMethodId;
        sbw.From = model.From;
        sbw.To = model.To;
        sbw.AdditionalFixedCost = model.AdditionalFixedCost;
        sbw.RatePerWeightUnit = model.RatePerWeightUnit;
        sbw.PercentageRateOfSubtotal = model.PercentageRateOfSubtotal;
        sbw.LowerWeightLimit = model.LowerWeightLimit;
        await _shippingByWeightService.UpdateShippingByWeightRecord(sbw);

        ViewBag.RefreshPage = true;

        return View(model);
    }
}